home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * FILE: LIFE.C
- *
- * DESCRIPTION: Windows 3.0 Version of the classic simulation of "LIFE".
- * This program incorporates a minor twist in the basic
- * algorithm by utilizing color to represent various
- * life "phases". The final phase of any life cycle is
- * always death!
- *
- * This software is hereby placed in the public domain.
- * Use and abuse it at your own risk!
- *
- *
- * AUTHOR: Tom Wheeler
- * 31294 Morlock
- * Livonia, Mich. 48152
- * [72037,1742]
- *
- *****************************************************************************
- *
- * DATE VER DESCRIPTION
- * ---------- --- ---------------------------------------------------
- * 05/20/91 1.0 Initial Development 1.0
- * 05/22/91 1.1 Added Color Support
- *
- ****************************************************************************/
-
- #include <windows.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include "life.h"
-
- #define CLASSNAME "LifeClass"
- #define APPNAME "Life"
-
- #define DEAD 0 /* state: cell is dead */
- #define ALIVE 0x1 /* state: cell is alive */
- #define CHILD 0x2 /* state: cell is a child */
- #define ADOLESCENT 0x4 /* state: cell is an adolescent */
- #define ADULT 0x8 /* state: cell is an adult */
- #define MIDAGED 0x10 /* state: cell is middle aged */
- #define RETIRED 0x20 /* state: cell is retirement age */
- #define SENIOR 0x40 /* state: cell is a senior citizen */
- #define METHUSULA 0x80 /* state: cell is to be terminated */
- #define AGECYCLE 10 /* # of cycles till next age */
-
- #define MAX_XCELL 100 /* max number of horizontal cells */
- #define MAX_YCELL 100 /* max number of vertical cells */
- #define DEFAULT_WIDTH 15 /* default number of cells to display */
- #define DEFAULT_HEIGHT 15 /* default number of cells to display */
- #define CYCLE_TIMER 1
-
- /* Macro to get a random integer within a specified range */
- #define getrandom( min, max ) ((rand() % (int)(((max)+1) - (min))) + (min))
-
- typedef unsigned char UCHAR;
-
- /* MATRIX defines the cell matrix used to represent the grid of entities.
- * Life states are represented as the low byte of the matrix entry, the high
- * byte is used to is used to keep a count representing the age of the
- * individual entities.
- */
- typedef int MATRIX[MAX_XCELL+2][MAX_YCELL+2];
-
- typedef struct _Life {
- int CellX; /* individual cell width */
- int CellY; /* individual cell height */
- int TopCellX; /* horiz. id of first cell displayed */
- int TopCellY; /* vert. id of frist cell displayed */
- int CellsPerPageX; /* num of visible X cells on screen */
- int CellsPerPageY; /* num of visible Y cells on screen */
- BOOL Grid; /* grid on/off state */
- BOOL Run; /* run state of matrix */
- MATRIX Matrix; /* state matrix */
- }LIFE;
- typedef LIFE *PLIFE;
-
- MATRIX Scratch; /* temporary cell matrix */
- HWND hInst = NULL; /* instance variable */
- HMENU hMenuFrame = NULL; /* instance menu handle */
- HWND hWndFrame = NULL; /* instance window handle */
- HANDLE hAccelFrame = NULL; /* instance keyboard accelerator */
- HANDLE hMatrix = NULL; /* handle to cell matrix structure */
-
- HPEN hBluePen = NULL; /* Blue drawing pen */
- HPEN hGreenPen = NULL; /* Green drawing pen */
- HPEN hCyanPen = NULL; /* Cyan drawing pen */
- HPEN hRedPen = NULL; /* Red drawing pen */
- HPEN hMagentaPen = NULL; /* Magenta drawing pen */
- HPEN hBrownPen = NULL; /* Brown drawing pen */
- HPEN hGrayPen = NULL; /* Gray drawing pen */
- HPEN hLightRedPen = NULL; /* Light Red drawing pen */
- HPEN hWhitePen = NULL; /* White drawing pen */
-
- HBRUSH hBlueBrush = NULL; /* Solid Blue brush */
- HBRUSH hGreenBrush = NULL; /* Solid Green brush */
- HBRUSH hCyanBrush = NULL; /* Solid Cyan brush */
- HBRUSH hRedBrush = NULL; /* Solid Red brush */
- HBRUSH hMagentaBrush = NULL; /* Solid Magenta brush */
- HBRUSH hBrownBrush = NULL; /* Solid Brown brush */
- HBRUSH hGrayBrush = NULL; /* Solid Gray brush */
- HBRUSH hLightRedBrush = NULL; /* Solid Light Red brush */
- HBRUSH hWhiteBrush = NULL; /* Solid White brush */
-
- PLIFE pLife = NULL; /* pointer to cell life structure */
- int iSmall; /* size in pixels of a small cell */
- int iNorm; /* size in pixels of a normal cell */
- int iLarge; /* size in pixels of a large cell */
- int iCycleTime = 250; /* default timer (milliseconds) */
- WORD wCycleTimer = 0; /* timer used for life cycling */
-
- /****************************************************************************
- * void DrawGridLines(HDC hDC,RECT *rect)
- *
- * Description: DrawsGridLines on the Life Display Window
- *
- * Input: hDC - Device Context to draw on
- * rect - pointer to client rectangle
- *
- * Output: N/A
- ****************************************************************************/
- void DrawGridLines(HDC hDC,RECT *rect)
- {
- int iX,iY;
-
- SelectObject(hDC,hGrayPen);
- for(iX = pLife->CellX; iX < rect->right; iX += pLife->CellX) {
- MoveTo(hDC,iX,0);
- LineTo(hDC,iX,rect->bottom);
- }
- for(iY = pLife->CellY; iY < rect->bottom; iY += pLife->CellY) {
- MoveTo(hDC,0,iY);
- LineTo(hDC,rect->right,iY);
- }
- }
-
- /****************************************************************************
- * void DrawCell(HDC hMouseMoveDC,int iXPos,int iYPos,UCHAR ucState)
- *
- * Description: Draws the cell at the indicated grid position in the color
- * appropriate to its current state.
- *
- * Input: hDC - Device Context to draw on
- * iXPos
- * iYPos - Screen Matrix position to draw at
- * ucState - State to draw
- *
- * Output: N/A
- ****************************************************************************/
- void DrawCell(HDC hDC,int iXPos,int iYPos,UCHAR ucState)
- {
- int iX,iY;
- HPEN hPen;
- HBRUSH hBrush;
-
- iX = iXPos * pLife->CellX;
- iY = iYPos * pLife->CellY;
- if(ucState & ALIVE) {
- if(ucState & SENIOR) {
- hPen = hBluePen;
- hBrush = hBlueBrush;
- }
- else if(ucState & RETIRED) {
- hPen = hBrownPen;
- hBrush = hBrownBrush;
- }
- else if(ucState & MIDAGED) {
- hPen = hMagentaPen;
- hBrush = hMagentaBrush;
- }
- else if(ucState & ADULT) {
- hPen = hRedPen;
- hBrush = hRedBrush;
- }
- else if(ucState & ADOLESCENT) {
- hPen = hCyanPen;
- hBrush = hCyanBrush;
- }
- else if(ucState & CHILD) {
- hPen = hGreenPen;
- hBrush = hGreenBrush;
- }
- }
- else {
- hPen = hWhitePen;
- hBrush = hWhiteBrush;
- }
- SelectObject(hDC,hPen);
- SelectObject(hDC,hBrush);
- Rectangle(hDC,iX+2,iY+2,iX+pLife->CellX-1,iY+pLife->CellY-1);
- }
-
- /****************************************************************************
- * void DrawMatrix(HDC hDC)
- *
- * Description: Draws The Matrix (only draws the cells that will be visible
- * in the display window)
- *
- * Input: hDC - Device Context to draw on
- *
- * Output: N/A
- ****************************************************************************/
- void DrawMatrix(HDC hDC)
- {
- int iX,iY,iXPos,iYPos,iCellTemp;
-
- for(iXPos = 0,iX = pLife->TopCellX;
- iX < pLife->CellsPerPageX + pLife->TopCellX; iX++,iXPos++) {
- for(iYPos = 0,iY = pLife->TopCellY;
- iY < pLife->CellsPerPageY + pLife->TopCellY; iY++,iYPos++) {
- iCellTemp = pLife->Matrix[iX][iY] & 0xff;
- if(iCellTemp & ALIVE)
- DrawCell(hDC,iXPos,iYPos,(UCHAR)iCellTemp);
- }
- }
- }
-
- /****************************************************************************
- * void CycleMatrix(HDC hDC)
- *
- * Description: Runs the Life Algorithm on the Cell Matrix (only updates
- * the cells that would be visible, the matrix is forced to
- * wrap at the limits of the screen matrix).
- *
- * Input: hDC - Device Context to draw on
- *
- * Output: N/A
- ****************************************************************************/
- void CycleMatrix(HDC hDC)
- {
- register int iX,iY;
- int iXPos,iYPos,iNeighbor,iCellTemp;
- UCHAR ucState;
- BOOL bNoneAlive = TRUE;
-
- for(iX = pLife->TopCellX,iXPos = 0; iX < (pLife->CellsPerPageX +
- pLife->TopCellX); iX++,iXPos++) {
- for(iY = pLife->TopCellY,iYPos = 0; iY < (pLife->CellsPerPageY +
- pLife->TopCellY); iY++,iYPos++) {
- iNeighbor = 0;
- if(pLife->Matrix[iX-1][iY] & ALIVE)
- iNeighbor++;
- if(pLife->Matrix[iX+1][iY] & ALIVE)
- iNeighbor++;
- if(pLife->Matrix[iX][iY-1] & ALIVE)
- iNeighbor++;
- if(pLife->Matrix[iX][iY+1] & ALIVE)
- iNeighbor++;
- if(pLife->Matrix[iX-1][iY-1] & ALIVE)
- iNeighbor++;
- if(pLife->Matrix[iX+1][iY+1] & ALIVE)
- iNeighbor++;
- if(pLife->Matrix[iX-1][iY+1] & ALIVE)
- iNeighbor++;
- if(pLife->Matrix[iX+1][iY-1] & ALIVE)
- iNeighbor++;
- ucState = (UCHAR)pLife->Matrix[iX][iY];
- if(ucState == DEAD) { /* birth of a cell if 3 neighbors present */
- if(iNeighbor == 3) {
- Scratch[iX][iY] = ALIVE | CHILD;
- DrawCell(hDC,iXPos,iYPos,ALIVE | CHILD);
- }
- else {
- Scratch[iX][iY] = pLife->Matrix[iX][iY];
- }
- }
- else {
- bNoneAlive = FALSE;
- if((iNeighbor < 2) || (iNeighbor > 3)) { /* kill it off */
- Scratch[iX][iY] = DEAD;
- DrawCell(hDC,iXPos,iYPos,DEAD);
- }
- else {
- /* Keep cell and increment cycle count. If cycle count limit
- * is reached, advance cell to next life cycle
- */
- Scratch[iX][iY] = pLife->Matrix[iX][iY] + 0x100;
- if(!((Scratch[iX][iY] & 0xff00) % (AGECYCLE << 8))) {
- iCellTemp = ((Scratch[iX][iY] & 0xff) << 1) | ALIVE;
- if(iCellTemp <= METHUSULA)
- Scratch[iX][iY] = (Scratch[iX][iY] & 0xff00) + iCellTemp;
- else {
- /* if it has aged past SENIOR, kill it off */
- Scratch[iX][iY] = iCellTemp = DEAD;
- }
- DrawCell(hDC,iXPos,iYPos,(UCHAR)iCellTemp);
- }
- }
- }
- }
- }
- /* copy all changes to permanent cell matrix */
- memmove(&pLife->Matrix,&Scratch,sizeof(MATRIX));
- /* randomize the matrix if no alive cells are displayed */
- if(bNoneAlive) {
- for(iX = pLife->TopCellX; iX < (pLife->CellsPerPageX +
- pLife->TopCellX); iX++) {
- for(iY = pLife->TopCellY; iY < (pLife->CellsPerPageY +
- pLife->TopCellY); iY++) {
- if(getrandom(0,1)) {
- pLife->Matrix[iX][iY] = ALIVE | CHILD;
- }
- }
- }
- }
- }
-
- /****************************************************************************
- * void UpdateScrollBarRange(HWND hWnd)
- *
- * Description: Updates the Scroll Bar Ranges
- *
- * Input: hWnd - Window Handle owning the scroll bars
- *
- * Output: N/A
- ****************************************************************************/
- void UpdateScrollBarRange(HWND hWnd)
- {
- RECT rect;
-
- GetClientRect(hWnd,&rect);
- pLife->CellsPerPageX = (rect.right / pLife->CellX) + 1;
- pLife->CellsPerPageY = (rect.bottom / pLife->CellY) + 1;
- pLife->TopCellX = max(1,min(pLife->TopCellX,MAX_XCELL -
- pLife->CellsPerPageX));
- pLife->TopCellY = max(1,min(pLife->TopCellY,MAX_YCELL -
- pLife->CellsPerPageY));
- SetScrollRange(hWnd,SB_HORZ,1,MAX_XCELL - pLife->CellsPerPageX,TRUE);
- SetScrollRange(hWnd,SB_VERT,1,MAX_YCELL - pLife->CellsPerPageY,TRUE);
- }
-
- /****************************************************************************
- * BOOL InitLife(void)
- *
- * Description: Life Initialization
- *
- * Input: N/A
- *
- * Output: Fails if no memory available
- ****************************************************************************/
- BOOL InitLife(void)
- {
- int iWidth,iHeight,iX,iY;
-
- /* allocate local storage to hold the Life Cell Matrix */
- if((hMatrix = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,
- sizeof(LIFE))) == NULL)
- return FALSE;
- pLife = (PLIFE)LocalLock(hMatrix); /* lock down the memory permanently */
-
- /* set the default Life cell values */
- iX = GetSystemMetrics(SM_CXSCREEN);
- iY = GetSystemMetrics(SM_CYSCREEN);
- iNorm = iY / 25;
- iSmall = iNorm / 2;
- iLarge = iNorm * 2;
- pLife->CellX = iNorm;
- pLife->CellY = iNorm;
- pLife->Grid = TRUE;
- pLife->Run = FALSE;
- pLife->TopCellX = pLife->TopCellY = 1;
- CheckMenuItem(hMenuFrame,MENU_NORM,MF_BYCOMMAND | MF_CHECKED);
- /* initialize all cells to DEAD */
- for(iWidth = 0; iWidth < MAX_XCELL; iWidth++)
- for(iHeight = 0; iHeight < MAX_YCELL; iHeight++)
- pLife->Matrix[iWidth][iHeight] = DEAD;
- iWidth = (pLife->CellX * DEFAULT_WIDTH) +
- (GetSystemMetrics(SM_CXFRAME) * 2) +
- GetSystemMetrics(SM_CXHTHUMB);
- iHeight = (pLife->CellY * DEFAULT_HEIGHT) +
- (GetSystemMetrics(SM_CYFRAME) * 2) +
- GetSystemMetrics(SM_CYMENU) +
- GetSystemMetrics(SM_CYVTHUMB) +
- GetSystemMetrics(SM_CYCAPTION);
- SetWindowPos(hWndFrame,NULL,(iX - iWidth) / 2,(iY - iHeight) / 2,
- iWidth,iHeight,SWP_NOZORDER);
- }
-
- /****************************************************************************
- * CenterDialog(HWND hDlg)
- *
- * Description: Function to Center a Dialog Box on the Screen
- *
- * Input: hDlg - Handle to Dialog Box to be centered
- *
- * Output: N/A
- *****************************************************************************/
- void CenterDialog(HWND hDlg)
- {
- RECT rect;
- int iX,iY,iNewX,iNewY;
-
- GetWindowRect(hDlg,(RECT far *)&rect);
- iX = GetSystemMetrics(SM_CXSCREEN);
- iY = GetSystemMetrics(SM_CYSCREEN);
- iNewX = (iX/2) - ((rect.right-rect.left)/2);
- iNewY = (iY/2) - ((rect.bottom-rect.top)/2);
- SetWindowPos(hDlg,NULL,max(iNewX,0),max(iNewY,0),rect.right-rect.left,
- rect.bottom-rect.top,SWP_NOZORDER);
- }
-
- /****************************************************************************
- *
- * BOOL FAR PASCAL TimerEditDlgProc(HWND hDlg,int iMessage,WORD wParam,
- * LONG lParam)
- *
- * DESCRIPTION: Life Cycle Time Edit Dialog Box Proc
- *
- * INPUT: hDlg - Handle to Dialog Box
- * iMessage - Dialog Box message
- * wParam
- * lParam - Standard Windows message parameters
- * Called externally from WINDOWS - Exported Function
- *
- * OUTPUT: N/A
- *
- ****************************************************************************/
- BOOL FAR PASCAL TimerEditDlgProc(HWND hDlg,int iMessage,WORD wParam,
- LONG lParam)
- {
- BOOL bTransFlag;
- WORD wVal;
- char szTime[10];
-
- switch (iMessage) {
- case WM_COMMAND:
- switch(wParam) {
- case IDOK:
- wVal = GetDlgItemInt(hDlg,TIMER_EDIT,(BOOL FAR *)&bTransFlag,
- FALSE);
- if((!bTransFlag) || (wVal < 100) || (wVal > 999)) {
- MessageBeep(0);
- sprintf(szTime,"%d",iCycleTime);
- SetDlgItemText(hDlg,TIMER_EDIT,(LPSTR)szTime);
- }
- else {
- iCycleTime = wVal;
- EndDialog(hDlg,TRUE);
- }
- break;
-
- case IDCANCEL:
- EndDialog(hDlg,FALSE);
- break;
- }
- break;
-
- case WM_INITDIALOG:
- sprintf(szTime,"%d",iCycleTime);
- SetDlgItemText(hDlg,TIMER_EDIT,(LPSTR)szTime);
- CenterDialog(hDlg);
- return(TRUE);
-
- default:
- return(FALSE);
- }
- return(FALSE);
- }
-
- /****************************************************************************
- * AboutDlgProc(hDlg,iMessage,wParam,lParam)
- *
- * Description: About Dialog Box Procedure
- *
- * Input: hDlg - Handle to Dialog Box
- * uMessage - Dialog Box message
- * wParam
- * lParam - Standard Windows message parameters
- * Called externally from WINDOWS
- *
- * Output: N/A
- *****************************************************************************/
- BOOL FAR PASCAL AboutDlgProc(HWND hDlg,unsigned iMessage,
- WORD wParam,LONG lParam)
- {
- BOOL Ret;
- char szTimeStamp[128];
-
- Ret = FALSE;
- switch (iMessage)
- {
- case WM_INITDIALOG:
- sprintf(szTimeStamp,"Built: %s %s",__DATE__,__TIME__);
- SetDlgItemText(hDlg,ABOUT_TIMESTAMP,szTimeStamp);
- CenterDialog(hDlg);
- Ret = TRUE;
- break;
-
- case WM_COMMAND:
- EndDialog(hDlg, TRUE);
- Ret = TRUE;
- break;
- }
- return Ret;
- }
-
- /****************************************************************************
- * WndProc(hWnd,iMessage,wParam,lParam)
- *
- * Description: Main Window Proc
- *
- * Input: hWnd - Handle to window
- * iMessage - Window message number
- * wParam,
- * lParam - Standard Windows message parameters
- * Called externally from WINDOWS
- *
- * Output: Calls DefWindowProc() while active,returns 0L ((LONG) FALSE)
- * when terminating.
- ****************************************************************************/
- long FAR PASCAL WndProc(HWND hWnd,unsigned iMessage,WORD wParam,LONG lParam)
- {
- FARPROC lpProc;
- long Ret;
- PAINTSTRUCT ps;
- static RECT rect;
- HDC hDC;
- WORD wXMouse,wYMouse;
- UCHAR ucState;
- static int iXDown,iYDown;
- static BOOL bMouseDown = FALSE,bIconic = FALSE;
- static HDC hMouseMoveDC = NULL;
- int iXCell,iYCell;
-
- Ret = (long)FALSE;
-
- switch(iMessage)
- {
- case WM_COMMAND:
- switch (wParam)
- {
- case MENU_RUN:
- if(pLife->Run) {
- /* stop the Cycle Timer */
- if(wCycleTimer) {
- KillTimer(hWnd,CYCLE_TIMER);
- wCycleTimer = 0;
- }
- ModifyMenu(hMenuFrame,MENU_RUN,MF_BYCOMMAND,MENU_RUN,
- "St&art\t^R");
- EnableMenuItem(hMenuFrame,MENU_STEP,MF_ENABLED);
- pLife->Run = FALSE;
- }
- else {
- /*start the cycle timer */
- if((wCycleTimer =
- SetTimer(hWnd,CYCLE_TIMER,iCycleTime,NULL)) == 0) {
- MessageBox(hWnd,"No More System Timers!",
- NULL,MB_OK | MB_ICONEXCLAMATION);
- break;
- }
- ModifyMenu(hMenuFrame,MENU_RUN,MF_BYCOMMAND,MENU_RUN,
- "St&op\t^R");
- pLife->Run = TRUE;
- EnableMenuItem(hMenuFrame,MENU_STEP,MF_GRAYED);
- }
- break;
-
- case MENU_STEP:
- hDC = GetDC(hWnd);
- CycleMatrix(hDC);
- ReleaseDC(hWnd,hDC);
- InvalidateRect(hWnd,NULL,FALSE);
- break;
-
- case MENU_CLEAR:
- /* if running, stop before clearing */
- if(pLife->Run)
- SendMessage(hWnd,WM_COMMAND,MENU_RUN,0L);
- for(iXCell = 0; iXCell < MAX_XCELL; iXCell++) {
- for(iYCell = 0; iYCell < MAX_YCELL; iYCell++) {
- pLife->Matrix[iXCell][iYCell] = DEAD;
- Scratch[iXCell][iYCell] = DEAD;
- }
- }
- InvalidateRect(hWnd,NULL,TRUE);
- break;
-
- case MENU_GRID:
- if(pLife->Grid) {
- ModifyMenu(hMenuFrame,MENU_GRID,MF_BYCOMMAND,MENU_GRID,
- "&Gridlines On\t^G");
- pLife->Grid = FALSE;
- }
- else {
- ModifyMenu(hMenuFrame,MENU_GRID,MF_BYCOMMAND,MENU_GRID,
- "&Gridlines Off\t^G");
- pLife->Grid = TRUE;
- }
- InvalidateRect(hWnd,NULL,TRUE);
- break;
-
- case MENU_TIMER:
- lpProc = MakeProcInstance((FARPROC) TimerEditDlgProc,hInst);
- DialogBox(hInst,"TIMERDLGBOX",hWnd,lpProc);
- FreeProcInstance(lpProc);
- /* if already running, update the timer */
- if(wCycleTimer) {
- KillTimer(hWnd,CYCLE_TIMER);
- if((wCycleTimer =
- SetTimer(hWnd,CYCLE_TIMER,iCycleTime,NULL)) == 0) {
- MessageBox(hWnd,"No More System Timers!",
- NULL,MB_OK | MB_ICONEXCLAMATION);
- break;
- }
- }
- break;
-
- case MENU_SMALL:
- CheckMenuItem(hMenuFrame,MENU_SMALL,MF_BYCOMMAND | MF_CHECKED);
- CheckMenuItem(hMenuFrame,MENU_NORM,MF_BYCOMMAND | MF_UNCHECKED);
- CheckMenuItem(hMenuFrame,MENU_LARGE,MF_BYCOMMAND | MF_UNCHECKED);
- pLife->CellX = iSmall;
- pLife->CellY = iSmall;
- UpdateScrollBarRange(hWnd);
- InvalidateRect(hWnd,NULL,TRUE);
- break;
-
- case MENU_NORM:
- CheckMenuItem(hMenuFrame,MENU_SMALL,MF_BYCOMMAND | MF_UNCHECKED);
- CheckMenuItem(hMenuFrame,MENU_NORM,MF_BYCOMMAND | MF_CHECKED);
- CheckMenuItem(hMenuFrame,MENU_LARGE,MF_BYCOMMAND | MF_UNCHECKED);
- pLife->CellX = iNorm;
- pLife->CellY = iNorm;
- UpdateScrollBarRange(hWnd);
- InvalidateRect(hWnd,NULL,TRUE);
- break;
-
- case MENU_LARGE:
- CheckMenuItem(hMenuFrame,MENU_SMALL,MF_BYCOMMAND | MF_UNCHECKED);
- CheckMenuItem(hMenuFrame,MENU_NORM,MF_BYCOMMAND | MF_UNCHECKED);
- CheckMenuItem(hMenuFrame,MENU_LARGE,MF_BYCOMMAND | MF_CHECKED);
- pLife->CellX = iLarge;
- pLife->CellY = iLarge;
- UpdateScrollBarRange(hWnd);
- InvalidateRect(hWnd,NULL,TRUE);
- break;
-
- case MENU_ABOUT:
- lpProc = MakeProcInstance((FARPROC) AboutDlgProc,hInst);
- DialogBox(hInst,"ABOUTBOX",hWnd,lpProc);
- FreeProcInstance(lpProc);
- break;
- }
- break;
-
- case WM_TIMER:
- hDC = GetDC(hWnd);
- CycleMatrix(hDC);
- ReleaseDC(hWnd,hDC);
- if(!bIconic)
- InvalidateRect(hWnd,NULL,FALSE);
- break;
-
- case WM_LBUTTONDOWN:
- iXDown = -1;
- iYDown = -1;
- bMouseDown = TRUE;
- hMouseMoveDC = GetDC(hWnd);
- GetClientRect(hWnd,&rect);
- SelectObject(hMouseMoveDC,GetStockObject(WHITE_PEN));
- break;
-
- case WM_LBUTTONUP:
- /* force draw at current position */
- SendMessage(hWnd,WM_MOUSEMOVE,wParam,lParam);
- if(bMouseDown) {
- bMouseDown = FALSE;
- SelectObject(hMouseMoveDC,GetStockObject(BLACK_PEN));
- ReleaseDC(hWnd,hMouseMoveDC);
- }
- break;
-
- case WM_MOUSEMOVE:
- if(bMouseDown) {
- wXMouse = LOWORD(lParam);
- wYMouse = HIWORD(lParam);
- /* translate mouse position into cell coordinates */
- iXCell = (int)wXMouse / pLife->CellX;
- iYCell = (int)wYMouse / pLife->CellY;
- if((iXCell != iXDown) || (iYCell != iYDown)) {
- iXDown = iXCell;
- iYDown = iYCell;
- ucState = (UCHAR)pLife->Matrix[iXCell+pLife->TopCellX]
- [iYCell+pLife->TopCellY];
- ucState = (UCHAR)((ucState & ALIVE) ? DEAD : ALIVE | CHILD);
- pLife->Matrix[iXCell+pLife->TopCellX]
- [iYCell+pLife->TopCellY] = ucState;
- DrawCell(hMouseMoveDC,iXCell,iYCell,ucState);
- }
- }
- break;
-
- case WM_NCMOUSEMOVE:
- /* look to see if the mouse is outside the client area, if so and
- * the mouse is being captured then release it
- */
- if(bMouseDown) {
- bMouseDown = FALSE;
- SelectObject(hMouseMoveDC,GetStockObject(BLACK_PEN));
- ReleaseDC(hWnd,hMouseMoveDC);
- }
- break;
-
- case WM_VSCROLL:
- switch(wParam) {
- case SB_LINEUP:
- pLife->TopCellY -= 1;
- break;
-
- case SB_PAGEUP:
- pLife->TopCellY -= pLife->CellsPerPageY;
- break;
-
- case SB_LINEDOWN:
- pLife->TopCellY += 1;
- break;
-
- case SB_PAGEDOWN:
- pLife->TopCellY += pLife->CellsPerPageY;
- break;
-
- case SB_THUMBPOSITION:
- pLife->TopCellY = LOWORD(lParam);
- break;
-
- default:
- break;
- }
- pLife->TopCellY = max(1,min(pLife->TopCellY,MAX_YCELL -
- pLife->CellsPerPageY));
- if(pLife->TopCellY != GetScrollPos(hWnd,SB_VERT)) {
- iXDown = -1;
- iYDown = -1;
- SetScrollPos(hWnd,SB_VERT,pLife->TopCellY,TRUE);
- InvalidateRect(hWnd,NULL,TRUE);
- }
- break;
-
- case WM_HSCROLL:
- switch(wParam) {
- case SB_LINEUP:
- pLife->TopCellX -= 1;
- break;
-
- case SB_PAGEUP:
- pLife->TopCellX -= pLife->CellsPerPageX;
- break;
-
- case SB_LINEDOWN:
- pLife->TopCellX += 1;
- break;
-
- case SB_PAGEDOWN:
- pLife->TopCellX += pLife->CellsPerPageX;
- break;
-
- case SB_THUMBPOSITION:
- pLife->TopCellX = LOWORD(lParam);
- break;
-
- default:
- break;
- }
- pLife->TopCellX = max(1,min(pLife->TopCellX,MAX_XCELL -
- pLife->CellsPerPageX));
- if(pLife->TopCellX != GetScrollPos(hWnd,SB_HORZ)) {
- iXDown = -1;
- iYDown = -1;
- SetScrollPos(hWnd,SB_HORZ,pLife->TopCellX,TRUE);
- InvalidateRect(hWnd,NULL,TRUE);
- }
- break;
-
- case WM_KEYDOWN:
- switch(wParam) {
- case VK_PRIOR:
- SendMessage(hWnd,WM_VSCROLL,SB_PAGEUP,0L);
- break;
-
- case VK_NEXT:
- SendMessage(hWnd,WM_VSCROLL,SB_PAGEDOWN,0L);
- break;
-
- case VK_UP:
- SendMessage(hWnd,WM_VSCROLL,SB_LINEUP,0L);
- break;
-
- case VK_DOWN:
- SendMessage(hWnd,WM_VSCROLL,SB_LINEDOWN,0L);
- break;
-
- case VK_LEFT:
- SendMessage(hWnd,WM_HSCROLL,SB_PAGEUP,0L);
- break;
-
- case VK_RIGHT:
- SendMessage(hWnd,WM_HSCROLL,SB_PAGEDOWN,0L);
- break;
- }
- break;
-
- case WM_SIZE:
- UpdateScrollBarRange(hWnd);
- break;
-
- case WM_PAINT:
- hDC = BeginPaint(hWnd,&ps);
- if(pLife->Grid)
- DrawGridLines(hDC,&ps.rcPaint);
- DrawMatrix(hDC);
- EndPaint(hWnd,&ps);
- break;
-
- case WM_SYSCOMMAND:
- switch(wParam) {
- case SC_MINIMIZE:
- bIconic = TRUE;
- break;
-
- case SC_MAXIMIZE:
- case SC_RESTORE:
- bIconic = FALSE;
- break;
- }
- return DefWindowProc(hWnd, iMessage, wParam, lParam);
- break;
-
- case WM_CREATE:
- hBluePen = CreatePen(PS_SOLID,1,RGB(0,0,128));
- hGreenPen = CreatePen(PS_SOLID,1,RGB(0,128,0));
- hCyanPen = CreatePen(PS_SOLID,1,RGB(0,128,128));
- hRedPen = CreatePen(PS_SOLID,1,RGB(128,0,0));
- hMagentaPen = CreatePen(PS_SOLID,1,RGB(128,0,128));
- hBrownPen = CreatePen(PS_SOLID,1,RGB(128,128,0));
- hGrayPen = CreatePen(PS_SOLID,1,RGB(192,192,192));
- hLightRedPen = CreatePen(PS_SOLID,1,RGB(255,0,0));
- hWhitePen = CreatePen(PS_SOLID,1,RGB(255,255,255));
- hBlueBrush = CreateSolidBrush(RGB(0,0,128));
- hGreenBrush = CreateSolidBrush(RGB(0,128,0));
- hCyanBrush = CreateSolidBrush(RGB(0,128,128));
- hRedBrush = CreateSolidBrush(RGB(128,0,0));
- hMagentaBrush = CreateSolidBrush(RGB(128,0,128));
- hBrownBrush = CreateSolidBrush(RGB(128,128,0));
- hGrayBrush = CreateSolidBrush(RGB(192,192,192));
- hLightRedBrush = CreateSolidBrush(RGB(255,0,0));
- hWhiteBrush = CreateSolidBrush(RGB(255,255,255));
- srand((unsigned)time(NULL));
- break;
-
- case WM_CLOSE:
- if(wCycleTimer) {
- KillTimer(hWnd,CYCLE_TIMER);
- wCycleTimer = 0;
- }
- if(hMatrix != NULL) {
- LocalUnlock(hMatrix);
- LocalFree(hMatrix);
- }
- DeleteObject(hBluePen);
- DeleteObject(hGreenPen);
- DeleteObject(hCyanPen);
- DeleteObject(hRedPen);
- DeleteObject(hMagentaPen);
- DeleteObject(hBrownPen);
- DeleteObject(hGrayPen);
- DeleteObject(hWhitePen);
- DeleteObject(hBlueBrush);
- DeleteObject(hGreenBrush);
- DeleteObject(hCyanBrush);
- DeleteObject(hRedBrush);
- DeleteObject(hMagentaBrush);
- DeleteObject(hBrownBrush);
- DeleteObject(hGrayBrush);
- DeleteObject(hWhiteBrush);
- PostQuitMessage(0);
- break;
-
- default:
- return DefWindowProc(hWnd, iMessage, wParam, lParam);
- }
- return 0L;
- }
-
- /****************************************************************************
- * int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,
- * LPSTR lpszCmdLine,int nCmdShow)
- *
- * Description: Life Main Window Function
- *
- * Input: hInstance - Window instance handle
- * hPrevInstance - Previous Instance Handle
- * lpszCmdLine - Window Activation Parameters (none req.)
- * nCmdShow - Show Window or Icon command
- * Called externally from WINDOWS
- *
- * Output: Handles Windows message loop,terminates to Windows
- *****************************************************************************/
- int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpszCmdLine,
- int nCmdShow)
- {
- HWND hWnd;
- MSG msg;
- WNDCLASS wc;
-
- hInst = hInstance;
- if(!hPrevInstance)
- {
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = WndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon(hInstance,"LIFEICON");
- wc.hCursor = LoadCursor(hInstance,"HAND");
- wc.hbrBackground = GetStockObject(WHITE_BRUSH);
- wc.lpszMenuName = "MainMenu";
- wc.lpszClassName = CLASSNAME;
-
- if(!RegisterClass(&wc)) {
- MessageBox(NULL, "Initialization Error!", APPNAME,
- MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
- return TRUE;
- }
- }
- hWnd = CreateWindow(CLASSNAME, /* Window class name */
- APPNAME, /* window caption */
- WS_OVERLAPPEDWINDOW | WS_VSCROLL |
- WS_HSCROLL, /* window style */
- CW_USEDEFAULT, /* initial x (horiz) position */
- CW_USEDEFAULT, /* initial y (vert) position */
- CW_USEDEFAULT, /* initial x size */
- CW_USEDEFAULT, /* initial y size */
- NULL, /* parent window handle */
- NULL, /* window menu handle */
- hInstance, /* program instance handle */
- NULL); /* create parameters */
-
-
- /* initialize variables */
- hWndFrame = hWnd; /* global parent window */
- hMenuFrame = GetMenu(hWnd); /* global menu handle */
- hAccelFrame = LoadAccelerators(hInstance,"LifeKeys"); /* key accelerator */
-
- /* initialize the Life cell structure */
- if(!InitLife())
- return TRUE;
-
- ShowWindow(hWnd,nCmdShow); /* shows the window */
-
- /* message loop */
- while(GetMessage(&msg,NULL,0,0)) {
- if(!TranslateAccelerator(hWnd,hAccelFrame,&msg)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- return msg.wParam;
- }
-